package practica2;

import java.util.Comparator;

public class Cromosoma {
	
	private Fila [] genotipo;
	private double aptitudDespl;
	private int edad;
	private int numCopias;
	private int cuadsBien; //Cuadriculas correctas
	private int colsBien; //Columnas correctas
	
	public Cromosoma(){
		genotipo = new Fila[9];
		for(int i=0;i<9;i++){
			genotipo[i] = new Fila();
		}
		edad = 0;
		numCopias = 1;
	}

	public Cromosoma(Cromosoma c){
		genotipo = new Fila[9];
		for(int i=0;i<9;i++){
			genotipo[i] = new Fila(c.genotipo[i]);
		}
		edad = 0;
		numCopias = 1;
	}
	
	public void setCasilla(int fil, int col, int val){
		if(val>0 && val<10){
			genotipo[fil-1].setFila(col-1, val);
		}
	}
	
	public void setCasillaFija(int fil, int col, int val){
		if(val>0 && val<10){
			genotipo[fil-1].setFila(col-1, val);
			genotipo[fil-1].setFija(col-1, true);
		}
	}
	
	public void setFija(int fil, int col, boolean fija){
		if(fil>0 && fil<10 && col>0 && col<10)
			genotipo[fil-1].setFija(col-1, fija);
	}
	
	public int getCasilla(int fil, int col){
		if(fil>0 && fil<10 && col>0 && col<10)
			return genotipo[fil-1].getFila(col-1);
		else	
			return 0;
	}
	
	public Fila getFila(int fil){
		if(fil>0 && fil<10)
			return genotipo[fil-1];
		else
			return null;
	}
	
	public void setFila(int fil, Fila fila){
		if(fil>0 && fil<10)
			genotipo[fil-1] = fila;
	}
	
	public boolean esFija(int fil, int col){
		if(fil>0 && fil<10 && col>0 && col<10)
			return genotipo[fil-1].getFija(col-1);
		else	
			return false;
	}
	
	public void rellenar(){
		for(int i=0;i<9;i++){
			genotipo[i].completarFila();
			genotipo[i].random();
		}
	}
	
	public void regenerar(int fila){
		Fila genCambio = genotipo[fila-1];
		for(int i=0;i<9;i++)
			if(!genCambio.getFija(i))
				genCambio.setFila(i, 0);
		genCambio.completarFila();
	}
	
	public void aumentarCopias(){
		numCopias++;
	}
	
	public void resetCopias(){
		numCopias = 0;
	}
	
	public int getCopias(){
		return numCopias;
	}
	
	public void aumentarEdad(){
		edad++;
	}
	
	public int getEdad(){
		return edad;
	}
	
	public void resetEdad(){
		edad = 0;
	}
	
	public Cromosoma clone(){
		return new Cromosoma(this);
	}

	public int[][] getFenotipo() {
		int [][] fenotipo = new int[9][9];
		for(int i=0;i<9;i++){
			for(int j=0;j<9;j++){
				fenotipo[i][j] = genotipo[i].getFila(j);
			}
		}
		return fenotipo;
	}

	public String getFenoString() {
		int [][] fenotipo = getFenotipo();
		String s = "";
		for (int i=0; i<9; i++) {
			for (int j=0; j<9; j++) {
				if(fenotipo[i][j]!=0)
					s += fenotipo[i][j] + " ";
				else
					s += "_ ";
			}
			s += "\n";
			
		}
		return s;
	}

	public double getAptitud(){
		cuadsBien = colsBien = 0;
		int[] sumaCuad = new int[9];
		int RS = 0;
		int[] sumaCol = new int[9];
		double[] productoCuad = new double[9];
		double[] productoCol = new double[9];
		double RP = 1;
		boolean[][] estaCuad = new boolean[9][10];
		boolean[][] estaCol = new boolean[9][10];
		int REA = 0;
		for(int i=0;i<9;i++){
			sumaCuad[i] = sumaCol[i] = 0;
			productoCol[i] = productoCuad[i] = 1;
			for(int j=1;j<10;j++)
				estaCuad[i][j] = estaCol[i][j] = false;
		}
		for(int i=0;i<9;i++){
			int fila = (i/3)*3;
			int columna = (i%3)*3;
			for(int j=fila;j<fila+3;j++){
				for(int k=columna;k<columna+3;k++){
					sumaCol[k] += genotipo[j].getFila(k);
					sumaCuad[i] += genotipo[j].getFila(k);
					estaCuad[i][genotipo[j].getFila(k)] = estaCol[k][genotipo[j].getFila(k)] = true;
					if(genotipo[j].getFila(k)!=0){
						productoCuad[i] *= genotipo[j].getFila(k);
						productoCol[k] *= genotipo[j].getFila(k);
					}
				}
			}
		}
		for(int j=0;j<9;j++){
			sumaCuad[j] = Math.abs(45 - sumaCuad[j]);
			sumaCol[j] = Math.abs(45 - sumaCol[j]);
			RS += sumaCuad[j] + sumaCol[j];
			productoCuad[j] = Math.sqrt(Math.abs(362880 - productoCuad[j]));
			productoCol[j] = Math.sqrt(Math.abs(362880 - productoCol[j]));
			RP += productoCuad[j] + productoCol[j];
			boolean cuadCompl, colCompl;
			cuadCompl = colCompl = true;
			for(int i=1;i<10;i++){				
				if(!estaCuad[j][i]){
					REA++;
					cuadCompl = false;
				}
				if(!estaCol[j][i]){
					REA++;
					colCompl = false;
				}
			}
			if(cuadCompl)
				cuadsBien++;
			if(colCompl)
				colsBien++;
		}
		return (10*RS)+(RP/10)+(20*REA);
	}
	
	static public String toString (boolean [] x){
		String s="";
		for(int i=0;i<x.length;i++){
			if(x[i])
				s+="1";
			else
				s+="0";
		}
		return s;
	}
	
	public String toString(){
		return getFenoString();
	}

	public double getAptitudDespl() {
		return aptitudDespl;
	}

	public void setAptitudDespl(double aptitudDespl) {
		this.aptitudDespl = aptitudDespl;
	}
	
	public int getCuadsBien(){
		getAptitud();
		return cuadsBien;
	}
	
	public int getColsBien(){
		getAptitud();
		return colsBien;
	}

	public static Comparator<Cromosoma> COMPARE_BY_FITNESS = new Comparator<Cromosoma>() {
        public int compare(Cromosoma c1, Cromosoma c2) {
        	return Double.compare(c1.getAptitudDespl(), c2.getAptitudDespl());
        }
    };
	
	
}